package multiThread;

import pojo.Person;

import java.time.LocalDateTime;
import java.util.concurrent.*;

/**
 * @projectName: java-sample
 * @description:
 * @author: Adam
 * @create: 2019-12-26 20:53
 **/

public class ThreadBase {

    /**
     * 创建线程的四种方式：
     * 1.继承Thread类
     *   public class MyThread extends Thread {
     *        public void run() {
     *          System.out.println("MyThread.run()");
     *          }
     *    }
     *   MyThread myThread1 = new MyThread();
     *   myThread1.start();
     * 2.实现Runnable接口
     *  public class MyThread extends OtherClass implements Runnable {
     *       public void run() {
     *          System.out.println("MyThread.run()");
     *          }
     *    }
     *  //启动MyThread，需要首先实例化一个Thread，并传入自己的MyThread实例：
     *   MyThread myThread = new MyThread();
     *   Thread thread = new Thread(myThread);
     *   thread.start();
     *   //事实上，当传入一个Runnable target参数给Thread后，Thread的run()方法就会调用 target.run() public
     * 3.实现Callable接口
     *    有返回值的任务必须实现Callable接口,会得到一个future对象
     * 4.基于线程池
     * 线程阻塞和就绪的区别：
     *   堵塞时，线程不能进入排队队列，只有当引起堵塞的原因被消除后，线程转入就绪状态。重新到就绪队列中排队等待，
     * 这时被CPU调度选中后会从原来停止的位置开始继续执行
     *
     * 注：Runable方式的多线程需要一个target参数，多个线程可以共享一个target，这种方式比较适合多个线程处理同一个任务
     *
     */

    static int value = 0;

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ThreadBase threadBase = new ThreadBase();
        threadBase.ThreadPool();
        System.out.println("主线程");
    }


    public void baseThread(){
        /**
         * 以下代码打印结果：
         *  线程1
         *  1
         *  主线程
         *  1
         *  线程2
         *  线程3
         *  3
         *  3
         *  比较随机。
         */

        //线程1
        new Runnable() {
            @Override
            public void run() {
                ThreadBase.value=1;
                System.out.println("线程1");
                System.out.println(ThreadBase.value);
            }
        }.run();

        //线程2
        new Thread(){
            @Override
            public void run(){
                ThreadBase.value=2;
                System.out.println("线程2");
                System.out.println(ThreadBase.value);
            }
        }.start();

        //匿名内部类只是声明一个线程，写好了run方法，并没有执行run方法，方法需要调用才会执行。
        // 线程的start方法才是启动线程，此时线程进入就绪状态，并没有运行，当执行run方法时，线程开始运行，run方法结束，线程随之结束。
        Thread myThread = new Thread(){
            @Override
            public void run(){
                ThreadBase.value=3;
                System.out.println("线程3");
                System.out.println(ThreadBase.value);
            }
        };

        //start()方法来启动线程，真正实现了多线程运行。这时无需等待run方法体代码执行完毕，可以直接执行下面的代码。
        myThread.start();
        //Thread.sleep(3000);
        System.out.println("主线程");
        System.out.println(ThreadBase.value);
    }

    /**
      * 实现 callable接口
      * @author jie
      * @param
      * @return
      * @date 2019/12/26 23:12
      */
      public void callableThread(){
          new Callable<Person>(){
              @Override
              public Person call(){
                  Person p = new Person();
                  p.setName("老王");
                  System.out.println("线程4");
                  //System.out.println(p.toString());
                 return p;
              }
          }.call();
      }



      /**
        * 线程池
        * newCachedThreadPool
        * newFixedThreadPool 创建一个可重用固定线程数的线程池，以共享的无界队列方式来运行这些线程。
        * newScheduledThreadPool
        * newSingleThreadExecutor
        * @author jie
        * @param
        * @return
        * @date 2019/12/27 19:43
        */
      public void ThreadPool() throws ExecutionException, InterruptedException {
          //创建线程池
          ExecutorService executorService = Executors.newFixedThreadPool(2);
          Callable myCallable = new Callable() {
              @Override
              public String call() throws Exception {
                  Thread.sleep(3000);

                  System.out.println(Thread.currentThread().getName());
                  return "call方法返回值1";
              }
          };

          Callable myCallable2 = new Callable() {
              @Override
              public String call() throws Exception {
                  Thread.sleep(3000);
                  System.out.println(Thread.currentThread().getName());
                  return "call方法返回值2";
              }
          };


          System.out.println("提交任务之前"+LocalDateTime.now());
          //线程执行是随机的，但是获取其返回值是根据代码的先后而有序的
          Future future = executorService.submit(myCallable);
          Future future2 = executorService.submit(myCallable2);
          System.out.println("提交任务之后，获取结果之前 "+ LocalDateTime.now());
          System.out.println("获取返回值:"+future.get().toString());
          System.out.println("获取返回值2:"+future2.get().toString());
          //main
          System.out.println(Thread.currentThread().getName());
          executorService.shutdown();
      }

}
